/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  DictManager.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2017/04/05
 *Desc		:  统一管理若干个DictTable
 *Relation :
 *Others	:
 *Function :
 *History	:
 ***************************************************************************************************/
#include "DictManager.h"

#include <bondlib/BondSpecialLabel.h>
#include <bondlib/QBIssuerInfo.h>
#include <core/FileSys.h>
#include <core/strings/Rand.h>
#include <core/strings/gbkmap.h>
#include <core/strings/string_convert.h>
#include <core/strings/string_util.h>
#include <core/system/system_util.h>
#include <thread>

#include "DictLoadListener.h"

using namespace qb::base;

#ifdef WIN32
#else
#define MAX_PATH 260
#define FIELD_OFFSET(type, field) ((long)(long)&(((type*)0)->field))
#define RTL_FIELD_SIZE(type, field) (sizeof(((type*)0)->field))
#endif

namespace qb {
namespace ht {
    bool syncAll = false;
    DictTable* tablesToInit[kDictTypeCount] = {};
    DictTable* tablesToLoad[kDictTypeCount] = {};
    void DictInitFunc(int index)
    {
        int nBegin, nEnd;
        if (index == 0)
        {
            nBegin = kDictTypeBondList;
            nEnd = kDictTypeIssuerInfo;
        }
        else
        {
            nBegin = kDictTypeIssuerInfo;
            nEnd = kDictTypeCount;
        }

        for (int i = nBegin; i < nEnd; i++)
        {
            DictTable* table = tablesToInit[i];
            if (table == nullptr)
                continue;
            string error;
            bool suc = table->Load(error);
            if (!suc)
                table->RecreateFile();
            log_warning("字典表%s 成功  %s", suc ? "加载" : "重新创建", suc ? "" : error.c_str());
        }

        log_warning("字典表thread:%d finished", index);
    }

    void DictLoadFunc(void* pData)
    {
        bool all = syncAll;
        DictManager* pManager = (DictManager*)pData;
        for (int i = 0; i < sizeof(tablesToLoad) / sizeof(void*); i++)
        {
            qb::base::HighResTime hst;
            DictTable* table = tablesToLoad[i];
            if (table == nullptr)
            {
                break;
            }
            kDictType type = table->GetType();
            if (type == kDictTypeMacroIndex)
            {
                pManager->UpdateMacroIndex(true);
                log_warning("[SyncToMemory[%d]] UpdateMacroIndex %d us", type, hst.elapsed().microsec());
                if (table)table->FlushCache();
                continue;
            }

            BASSERT(table/*, "invalid kDictType:%d Name:%s", type, DictDesc::GetStockDictDesc(type).GetName().c_str()*/);
            if (table == NULL)
                continue;

            RecordEnumerator enumerator(table, all);
            log_warning("[SyncToMemory[%d]] enumerator %d us", type, hst.elapsed().microsec());
            hst = qb::base::HighResTime();
            if (enumerator.IsEmpty())
                continue;
            int sz = enumerator.GetRecordCount();
            pManager->GetLoadListener()->LoadRecords(enumerator, type);
            int cost = hst.elapsed().microsec();
            log_warning("[SyncToMemory[%d]] LoadRecords size = %d, cost %d us, %.2f us each", type, sz, cost, cost * 1.0 / sz);
        }

        log_warning("[SyncToMemory] BondContainer finished");
    }

DictManager::DictManager()
    : m_clear_table(false), m_notify_count(0), m_initialized(false) {}
DictManager::~DictManager() {
  if (m_loadlistener) delete m_loadlistener;
  DictTableMapIt it = m_tables.begin();
  for (; it != m_tables.end(); ++it) {
    DictTable* table = it->second;
    if (table) {
      table->Unload();
      delete table;
      it->second = NULL;
    }
  }
  m_tables.clear();
}
void DictManager::Init() {
  if (m_initialized) return;
  // BS_METRICS("DictManager");
  m_initialized = true;
  m_clear_table = false;
  m_loadorder.push_back(kDictTypeBondDict);
  m_loadorder.push_back(kDictTypeProvinceInfo);
  m_loadorder.push_back(kDictTypeSwsectorInfo);
  m_loadorder.push_back(kDictTypeSwsectorInfo2021);
  m_loadorder.push_back(kDictTypeIssuerInfo);
  m_loadorder.push_back(kDictTypeUnderwriter);
  m_loadorder.push_back(kDictTypeContinuousContractInfo);
  m_loadorder.push_back(kDictTypeExchangeRepo);
  m_loadorder.push_back(kDictTypeBondList);
  m_loadorder.push_back(kDictTypeBondPrimaryInfo);
  m_loadorder.push_back(kDictTypeBondAdditionInfo);
  m_loadorder.push_back(kDictTypeBondOptionInfo);
  m_loadorder.push_back(kDictTypeBondAuctionInfo);
  m_loadorder.push_back(kDictTypeABSBond);
  m_loadorder.push_back(kDictTypeBondCRMClause);
  m_loadorder.push_back(kDictTypeBondCDCAuth);
  m_loadorder.push_back(kDictTypeBondHoliday);
  m_loadorder.push_back(kDictTypeMacroIndex);
  m_loadorder.push_back(kDictTypeFinancialCompany);
  m_loadorder.push_back(kDictTypeMainUnderwriter);
  m_loadorder.push_back(kDictTypeSpecialLabelInfo);
  m_loadorder.push_back(kDictTypeBondSpecialLabel);
  m_loadlistener = new DictLoaderListener(kDictTypeBondList);
  m_sequence_log = false;

  if (m_clear_table)
  {
      return;
  }

  DictDesc::GetStockDictDesc(kDictTypeBondList);

  for (int i = kDictTypeBondList; i < kDictTypeCount; i++)
  {
      const DictDesc& dd = DictDesc::GetStockDictDesc(i);
      DictTable* table = new DictTable(dd);
      if (i != kDictTypeBondKongfu)
      {
          m_tables[(kDictType)i] = table;
          tablesToInit[i] = table;
      }
  }

  std::thread threadInit(DictInitFunc, 1);
  DictInitFunc(0);
  if (threadInit.joinable())
      threadInit.join();

  for (int i = kDictTypeBondList; i < kDictTypeCount; i++)
  {
      if (i != kDictTypeBondKongfu)
      {
          UpdateDictState(m_tables[(kDictType)i]);
      }
  }
}
DictTable* DictManager::GetDictTable(kDictType id) {
  DictTable* table = GetTablePtr(id);
  if (table == NULL) {
    AddDictTable(id);
    table = GetTablePtr(id);
  }
  BASSERT(table != NULL);
  return table;
}
DictTable* DictManager::GetTablePtr(kDictType id) {
  BASSERT(id >= 0 && id < kDictTypeCount);
  DictTableMap::iterator it = m_tables.find(id);

  DictTable* table = it != m_tables.end() ? it->second : NULL;
  return table;
}
bool DictManager::RecreateTable(kDictType type) {
  BASSERT(type >= 0 && type < kDictTypeCount);
  DictTableMap::iterator it = m_tables.find(type);
  if (it != m_tables.end()) {
    DictTable* exist = it->second;
    if (exist) {
      exist->RecreateFile();
      delete exist;
    }
    m_tables.erase(it);
  }
  AddDictTable(type);
  DictTable* newTable = GetTablePtr(type);
  BASSERT(newTable);
  return false;
}
void DictManager::AddDictTable(kDictType type) {
  if (GetTablePtr(type) != NULL) return;

  std::string error;
  const DictDesc& dd = DictDesc::GetStockDictDesc(type);
  // BS_METRICS("加载字典%s", dd.GetName().c_str());
  DictTable* table = new DictTable(dd);
  bool suc = table->Load(error);
  if (!suc) table->RecreateFile();
  log_warning("字典表%s 成功  %s", suc ? "加载" : "重新创建",
              suc ? "" : error.c_str());
  BASSERT(table && type >= 0 && type < kDictTypeCount);
  m_tables[type] = table;
  UpdateDictState(table);
}
void DictManager::UpdatePack(UpdatePacket* raw, bool all) {
  DictTable* table = GetDictTable(raw->type);
  BASSERT(table);
  if (table) {
    table->UpdatePack(raw, all);
    if (raw->type != kDictTypeMacroIndex) UpdateDictState(table);
    UpdateDictHistory(raw->type, raw->updateId, raw->szMd5);
  }
}
void DictManager::UpdateDictHistory(kDictType type, int updateid,
                                    const char* md5) {
  auto it = m_table_history.find(type);
  if (it == m_table_history.end()) {
    m_table_history[type] = DictHistory();
    it = m_table_history.find(type);
  }
  DictState ds;
  ds.type = type;
  ds.updateid = updateid;
  FIELDCOPY(ds.md5, md5);
  it->second.insert(DictHistory::value_type(updateid, ds));
}
int DictManager::GetUpdateIdBefore(kDictType type, int updateid, char* md5,
                                   int capcity) {
  auto it = m_table_history.find(type);
  if (it != m_table_history.end()) {
    DictHistory& hist = it->second;
    auto hit = hist.lower_bound(updateid);
    if (hit != hist.end()) {
      hit--;
      if (hit != hist.end()) {
        FIELDCOPYN(md5, capcity, hit->second.md5);
        return hit->first;
      }
    }
  }
  return -1;
}
bool DictManager::HasBadDict() {
  for (int i = 0; i < kDictTypeCount; i++) {
    kDictType type = (kDictType)i;
    int predictsize = 0, updateid = 0;
    const char* md5 = GetDictState(type, updateid);
    if (md5 == 0 || strlen(md5) <= 0 || updateid == 0) {
      log_warning("Dict %d has problem!", type);
      return true;
    }
  }
  return false;
}
void DictManager::RemoveBondSpecialLabel(bool all) {
  // 只处理特殊标签增量删除，底层代码有个BUG,删除记录时，在字典文件里做了删除标志
  // 然后直接将该记录从缓存中删除了，导致RecordEnumerator中从缓存中找不到该条被删除的记录
  // 为了不影响其他字典功能，所以只能在这里特殊处理
  DictTable* table = GetDictTable(kDictTypeBondSpecialLabel);
  if (all || !table) {
    return;
  }

  char combBondKey[40] = {0};
  char labelId[16] = {0};
  BondSpecialLabelMgr& bslm = BondSpecialLabelMgr::instance();
  const DictTable::RecordStateMap& sets =
      table->GetLastUpdateSet().GetStateMap();
  for (auto it = sets.begin(); it != sets.end(); ++it) {
    const std::string& key = it->first;
    const DictTable::RecordState& rs = it->second;
    if (key.empty() || !rs.removed) {
      continue;
    }

    const char* keyBuf = key.c_str();
    const char* dotstr = strrchr(keyBuf, '.');
    int dot = dotstr ? (dotstr - keyBuf) : (-1);
    if (dot <= 0) {
      continue;
    }

    memset(combBondKey, 0, sizeof(combBondKey));
    memset(labelId, 0, sizeof(labelId));
    FIELDCOPYN(combBondKey, dot + 1, keyBuf);
    FIELDCOPY(labelId, keyBuf + dot + 1);
    bslm.removeLabel(combBondKey, labelId);
    log_debug(
        "[SyncToMemory[%d]] remove bond special label, labelId:%s, "
        "combBondKey:%s",
        kDictTypeBondSpecialLabel, labelId, combBondKey);
  }
}
void DictManager::UpdateMacroIndex(bool all) {
  DictTable* table = GetDictTable(kDictTypeMacroIndex);
  BASSERT(table);
  if (table) {
    table->UpdateMacroIndex(all);
    UpdateDictState(table);
  }
}
int DictManager::SyncToMemory(bool all) {
    int issue_count = 0;
    int nTypesOnBondList = 0;
    int nTypesNoBondList = 0;
    DictTable* tablesOnBondList[kDictTypeCount] = {};
    DictTable* tablesNoBondList[kDictTypeCount] = {};
    for (int i = 0; i < (int)m_loadorder.size(); i++)
    {
        kDictType type = m_loadorder.at(i);
        if (all || IsDataUpdated(type))
        {
            log_warning("[SyncToMemory[%d]] start", type);
            if (type == kDictTypeBondList ||
                type == kDictTypeBondPrimaryInfo ||
                type == kDictTypeBondCDCAuth ||
                type == kDictTypeABSBond ||
                type == kDictTypeBondAdditionInfo ||
                type == kDictTypeBondConversion ||
                type == kDictTypeBondDefaulted ||
                type == kDictTypeBondOptionInfo ||
                type == kDictTypeBondAuctionInfo
                )
            {
                tablesOnBondList[nTypesOnBondList++] = GetDictTable(type);
            }
            else
            {
                tablesNoBondList[nTypesNoBondList++] = GetDictTable(type);
                memcpy(tablesToLoad, tablesNoBondList, sizeof(tablesNoBondList));
            }
        }
    }

    syncAll = all;
    std::thread t(DictLoadFunc, this);
    for (int i = 0; i < (int)nTypesOnBondList; i++)
    {
        qb::base::HighResTime hst;
        DictTable* table = tablesOnBondList[i];
        kDictType type = table->GetType();
        if (type == kDictTypeMacroIndex)
        {
            UpdateMacroIndex(true);
            log_warning("[SyncToMemory[%d]] UpdateMacroIndex %d us", type, hst.elapsed().microsec());
            if (table)table->FlushCache();
            continue;
        }
        if (type == kDictTypeBondSpecialLabel) {
            RemoveBondSpecialLabel(all);
        }
        BASSERT(table/*, "invalid kDictType:%d Name:%s", type, DictDesc::GetStockDictDesc(type).GetName().c_str()*/);
        if (table == NULL)
            continue;

        RecordEnumerator enumerator(table, all);
        log_warning("[SyncToMemory[%d]] enumerator %d us", type, hst.elapsed().microsec());
        hst = qb::base::HighResTime();
        if (enumerator.IsEmpty())
            continue;
        int sz = enumerator.GetRecordCount();
        m_loadlistener->LoadRecords(enumerator, type);
        int cost = hst.elapsed().microsec();
        log_warning("[SyncToMemory[%d]] LoadRecords size = %d, cost %d us, %.2f us each", type, sz, cost, cost * 1.0 / sz);
        if (type == kDictTypeBondAdditionInfo || type == kDictTypeBondPrimaryInfo)
            issue_count++;

        if (m_sequence_log)
        {
            vector<int> sequences;
            GetDictSequence(type, sequences);
            SaveSequences(sequences, type, "notify", m_notify_count);
        }
        table->FlushCache();
    }
    log_warning("[SyncToMemory] Non BondContainer finished");
    m_notify_count++;
    if (t.joinable())
        t.join();
    return issue_count;
}

DictLoaderListener* DictManager::GetLoadListener()
{
    return m_loadlistener;
}
void DictManager::UpdateDictState(DictTable* table) {
  DictState state;
  memset(&state, 0, sizeof(DictState));
  state.type = table->GetType();
  state.updateid = table->GetUpdateId();
  memcpy(state.md5, table->GetMd5State(), sizeof(tName64));

  SCOPED_LOCK(m_state_lock);
  m_table_states[state.type] = state;
}
void DictManager::Clear() {
  // BS_METRICS("[DICT]");
  DictTableMapIt it = m_tables.begin();
  for (; it != m_tables.end(); ++it) {
    DictTable* table = it->second;
    if (table) {
      UpdateDictState(table);
      table->Unload();
      if (m_clear_table) {
        delete table;
        it->second = NULL;
      }
    }
  }
  if (m_clear_table) m_tables.clear();
}
void DictManager::ClearSeqSet() {
  DictTableMapIt it = m_tables.begin();
  for (; it != m_tables.end(); ++it) {
    DictTable* table = it->second;
    if (table) table->ClearSeqSet();
  }
}
const char* DictManager::GetDictState(kDictType type, int& updateid) {
  BASSERT(type < kDictTypeCount);
  if (GetTablePtr(type) == NULL) {
    AddDictTable(type);
  }

  SCOPED_LOCK(m_state_lock);
  DictStateMap::iterator it = m_table_states.find(type);
  BASSERT(it != m_table_states.end());
  updateid = it->second.updateid;
  return it->second.md5;
}
bool DictManager::HasEmptyDict() {
  for (int i = 0; i < kDictTypeCount; i++) {
    kDictType type = (kDictType)i;
    DictTable* table = GetDictTable(type);
    if (table == NULL) return true;
    if (table->GetMaxRecordId() <= 0) return true;
  }
  return false;
}
bool DictManager::GetDictSequence(kDictType type, std::vector<int>& sequences) {
  sequences.clear();
  DictTable* table = GetDictTable(type);
  if (table) {
    return table->GetSequences(sequences);
  }
  return false;
}
bool DictManager::IsDataUpdated(kDictType type) {
  return GetLastUpdateSetSize(type) > 0;
}
bool DictManager::IsAnyDataUpdate() {
  for (int i = 0; i < (int)m_loadorder.size(); i++) {
    kDictType type = m_loadorder.at(i);
    if (GetLastUpdateSetSize(type) > 0) {
      return true;
    }
  }
  return false;
}
int DictManager::GetLastUpdateSetSize(kDictType type) {
  DictTable* table = GetTablePtr(type);
  return table ? table->GetLastUpdateSetSize() : 0;
}
void DictManager::ClearUpdateSet() {
  // 清理最近的一个更新包带来的记录印记
  for (int i = 0; i < (int)m_loadorder.size(); i++) {
    kDictType type = m_loadorder.at(i);
    if (IsDataUpdated(type)) {
      DictTable* table = GetTablePtr(type);
      if (table) table->ClearUpdateSet();  //???宏观指标需要特殊处理
    }
  }
}
int DictManager::SimulateModifyBondList() {
  // 在"DictSimulateModifyPack"开启的情况下,每间隔5秒中检测一次文件是否存在
  int processed = 0;
  static DWORD lastcheck = 0;
  if (GetTickCount() - lastcheck >= 5000) {
    lastcheck = GetTickCount();
    const wchar_t* fname = L"dict_simulate_pack.txt";
#ifdef WIN32
    DWORD dwatt = GetFileAttributesW(fname);
    if (dwatt != INVALID_FILE_ATTRIBUTES && !(dwatt & FILE_ATTRIBUTE_DIRECTORY))
#endif
    {
      std::vector<BaseString> lines;
      qb::base::StringUtil::LoadLinesFromFile(fname, lines);
      if (lines.size() == 4) {
        std::string table_name = lines[0].c_str();
        BaseString& key = lines[1];
        BaseString& name = lines[2];
        BaseString& value = lines[3];
        kDictType type = kDictTypeCount;
        for (int i = 0; i < kDictTypeCount; i++) {
          if (DictDesc::GetStockDictDesc(i).GetName() == table_name) {
            type = (kDictType)i;
          }
        }
        if (type != kDictTypeCount) {
          DictTable* table = GetDictTable(type);
          if (table) {
            char keybuf[256] = {0};
            memset(keybuf, 0, 256);
            memcpy(keybuf, key.c_str(), key.size());
            table->UpdateModifyPack(keybuf, name.c_str(), value.c_str());
          }
        }
      }
      lines.clear();
      qb::base::StringUtil::WriteLines(lines, W2G(fname));
    }
  }
  return processed;
}
int DictManager::GetRecordCount(kDictType type) {
  DictTable* table = GetTablePtr(type);
  return table ? table->GetRecordCount() : 0;
}
void DictManager::ExportData(const char* fullDirectory) {
  qb::base::BaseString path, name;
  qb::base::StringUtil::SplitFileName(fullDirectory, path, name);
  FileSys::instance()->makeSlashPath(path);

  for (int i = 0; i < (int)m_loadorder.size(); i++) {
    kDictType type = m_loadorder.at(i);
    DictTable* table = GetDictTable(type);
    if (table == NULL) continue;

    std::string tablename = table->GetName();
    const char* dot = strchr(tablename.c_str(), '.');
    if (dot) {
      tablename = tablename.substr(0, dot - tablename.c_str()) + ".cod";
    }
    std::string fullName = path.c_str() + tablename;
    table->Export(fullName.c_str());
  }

  std::vector<BaseString> lines;
  lines.push_back("[PatchName]");
  for (int i = 0; i < kDictTypeCount; i++) {
    kDictType type = (kDictType)i;
    DictTable* table = GetTablePtr(type);
    if (table)
      lines.push_back(qb::base::os::fmtstr("%s=%s_%d", table->GetName(),
                                           table->GetMd5State(),
                                           table->GetUpdateId()));
  }
  qb::base::StringUtil::WriteLines(lines, path + "Md5.txt");
}
void DictManager::DumpStatus(int mode) {
  for (int i = 0; i < kDictTypeCount; i++) {
    kDictType type = (kDictType)i;
    DictTable* table = GetTablePtr(type);
    if (table) {
      table->DumpStatus(mode);
    }
  }
}
void DictManager::SaveSequences(const std::vector<int>& sequences,
                                kDictType type, const char* tag, int id) {
  if (!m_sequence_log) return;
  if (type >= kDictTypeCount) return;
  const DictDesc& dd = DictDesc::GetStockDictDesc(type);
  BaseString apppath = FileSys::instance()->dataDir().toStdString().c_str();
  char path[MAX_PATH] = {0};
  FMTBUF(path, "%s/BondData/seq", apppath.c_str());
  FileSys::instance()->makePathExist(path);
  FMTBUF(path, "%s/BondData/seq/%s_%s_%d.txt", apppath.c_str(),
         dd.GetName().c_str(), tag, id);
  CBufferFile bufferfile(path, 1024 * 1024);
  char buffer[128] = {0};
  for (int i = 0; i < (int)sequences.size(); i++) {
    int len = FMTBUF(buffer, "%d", sequences[i]);
    bufferfile.AddLine(buffer, len);
  }
}
int DictManager::PredictProgressSize() {
  // 根据当前各个字典状态,评估可能要处理的数据规模大小
  int total = 0;
  for (int i = 0; i < kDictTypeCount; i++) {
    kDictType type = (kDictType)i;
    int predictsize = 0, updateid = 0;
    const char* md5 = GetDictState(type, updateid);
    if (md5 == 0 || strlen(md5) <= 0 || updateid == 0)
      predictsize = DictDesc::GetStockDictDesc(type).GetPredictSize();
    else
      predictsize = 1000;
    total += predictsize;
  }
  return total;
}
qb::ht::kDictType DictManager::GetPackType(const char* buf, int size) {
  DictTable::PackHeader head = *((DictTable::PackHeader*)buf);
  std::vector<const char*> fields;
  int pack_headsize =
      FIELD_OFFSET(DictTable::PackHeader, PackHeader::FieldCount) +
      RTL_FIELD_SIZE(DictTable::PackHeader, PackHeader::FieldCount);
  const char* field_start = buf + pack_headsize;
  for (int i = 0; i < head.FieldCount; i++) {
    fields.push_back(field_start);
    field_start += strlen(field_start) + 2;
  }

  int match[kDictTypeCount] = {0};
  for (int i = 0; i < (int)kDictTypeCount; i++) match[i] = 0;
  for (int i = 0; i < (int)kDictTypeCount; i++) {
    const DictDesc& dd = DictDesc::GetStockDictDesc(i);
    // if ((int)fields.size() > dd.GetColumnCount())
    //{
    //	match[i] = -1;
    //	continue;
    // }
    for (int k = 0; k < (int)fields.size(); k++) {
      if (match[i] < 0) continue;
      if (dd.HasColumn(fields[k])) match[i] = match[i] + 1;
    }
  }
  int select = -1;
  double score_max = 0.0;
  for (int i = 0; i < kDictTypeCount; i++) {
    const DictDesc& dd = DictDesc::GetStockDictDesc(i);
    if (match[i] <= 0) continue;
    double score = match[i] * 1.0 / dd.GetColumnCount();
    if (score > score_max) {
      score_max = score;
      select = i;
    }
  }
  BASSERT(select >= 0);
  return select >= 0 ? (kDictType)select : kDictTypeCount;
}

int DictManager::UnitTest() {
  /*	BaseString path = "C:/Projects/QBDev/quoteboard/bin_vc12/release/data/";
                  vector<BaseString> binfiles;
                  StringUtil::SearchFiles(path, "*.bin", false, binfiles);
                  struct PackInfo{
                          int		index;
                          int		updateid;
                          int		size;
                          string	md5;
                          string	file;
                          char*	fbuf;
                          int		fsize;
                          PackInfo(const PackInfo& pi) :index(pi.index),
     updateid(pi.updateid), size(pi.size), md5(pi.md5), file(pi.file), fbuf(0),
     fsize(0){} PackInfo(const char* fname) :file(fname)
                          {
                                  BaseString path, base;
                                  StringUtil::SplitFileName(fname, path, base);
                                  strinfo tokens[128] = { 0 };
                                  int tknum =
     StringUtil::SplitStringInfo(base.c_str(), base.size(), "_", tokens, 128);
                                  BASSERT(tknum > 4);
                                  //
     8_0_211714_352977D53C8EB00906DCA4546FAB67102670FA0E_46525.bin index =
     atoi(base.c_str() + tokens[0].pos); updateid = atoi(base.c_str() +
     tokens[2].pos); md5 = BaseString(base.c_str() + tokens[3].pos,
     tokens[3].len); size = atoi(base.c_str() + tokens[4].pos);
                          }
                          ~PackInfo()
                          {
                                  if (fbuf)	delete[] fbuf;
                          }
                          PackInfo& operator=(const PackInfo& pi){
                                  index = pi.index; updateid = pi.updateid; size
     = pi.size; md5 = pi.md5; file = pi.file; return *this;
                          }
                          bool operator<(const PackInfo& pi)const
                          {
                                  if (index == pi.index)
                                          return updateid < pi.updateid;
                                  return index < pi.index;
                          }
                  };
      std::vector<PackInfo> files;
                  for (int i = 0; i < (int)binfiles.size(); i++)
                  {
                          files.push_back(binfiles[i].c_str());
                  }
                  std::sort(files.begin(), files.end());


                  for (int i = 0; i < (int)files.size(); i++)
                  {
                          int fsize = 0;
                          PackInfo& pack = files[i];

          WideString strWide = qb::base::U2W(pack.file.c_str(),
     pack.file.length()); pack.fbuf =
     StringUtil::LoadFileContent(strWide.c_str(), pack.fsize);
                  }


                  DictManager dm;
                  {
      //	BS_METRICS("DictManager");
                          for (int i = 0; i < (int)files.size(); i++)
                          {
                                  PackInfo& pack = files[i];
                                  DictTable* table =
     dm.GetDictTable((kDictType)i);
                                  //table->UpdatePack(pack.fbuf, pack.fsize,
     pack.md5.c_str(), pack.updateid,false);
                          }
                  }




                  //DictTable
     dict(DictDesc::GetStockDictDesc(kDictTypeBondList));
                  //string error;
                  //BS_METRICS("Load");
                  //if (!dict.Load(error))
                  //{
                  //	dict.RemoveFile();

                  //	int fsize = 0;
                  //	int updateid = 188296;
                  //	string md5 = "AB18D1F51EE07A92ED7D5C8EAF744ED6D337270C";
                  //	string fpack =
     "C:/Projects/QBDev/quoteboard/bin_vc12/release/data/0_0_188296_AB18D1F51EE07A92ED7D5C8EAF744ED6D337270C_25770765.bin";
                  //	char* fbuf = StringUtil::LoadFileContent(fpack.c_str(),
     fsize);
                  //	dict.UpdatePack(fbuf, fsize, md5.c_str(), updateid);
      //}*/
  return 1;
}

}  // namespace ht
}  // namespace qb
